package lock;

import java.util.LinkedList;

/**
 * 案例：使用synchronized关键字实现生产者-消费者队列
 */
public class WaitNotifyQueue<T> {

    private final LinkedList<T> queue = new LinkedList<>();
    private final static int MAX_COUNT = 10;//队列最大长度

    public synchronized void put(T resource) throws InterruptedException {
        while (queue.size() >= MAX_COUNT) {
            //队列满了，不能再塞东西了，轮询等待消费者取出数据
            System.out.println("生产者:队列已满，无法插入...");
            this.wait();//被唤醒后队列可能已经被前面唤醒的生产者重新填满了，故需循环判断
        }
        System.out.println("生产者:插入"+resource + "! ! !");
        queue.addFirst(resource);
        this.notifyAll();
    }

    public synchronized void take() throws InterruptedException {
        while (queue.size() <= 0) {
            //队列空了，不能再取东西,轮询等待生产者插入数据
            System.out.println("消费者:队列为空，无法取出...");
            this.wait();//被唤醒后队列仍可能为空，故需循环判断
        }
        System.out.println("消费者:取出消息! !!");
        queue.removeLast();
        this.notifyAll();
    }
}

class Test {
    public static void main(String[] args) {
        WaitNotifyQueue<String> waitNotifyQueue = new WaitNotifyQueue<>();
        //生产者线程 可多个
        new Thread(() -> {
            for (int i = 0;i<100;i++) {
                try {
                    waitNotifyQueue.put("消息" + Thread.currentThread().getName() + i);//生产
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        //消费者线程 可多个
        new Thread(() -> {
            for (int i = 0;i<100;i++) {
                try {
                    waitNotifyQueue.take();//消费
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
